using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Automation;

namespace IppPrinterInstallHelper
{
    internal sealed class MainForm : Form
    {
        private const int ServerPort = 36669;
        private const string RequestMagic = "IPP_DISCOVERY_REQUEST";

        private readonly ListView _printerListView;
        private readonly Button _nextButton;
        private readonly Button _cancelButton;
        private readonly Label _titleLabel;
        private readonly Label _subtitleLabel;
        private readonly LinkLabel _refreshLinkLabel;
        private readonly LinkLabel _linkLabel;
        private readonly ProgressBar _progressBar;

        private readonly ImageList _imageList;
        private readonly Bitmap _printerBitmap;

        private readonly List<DiscoveredPrinter> _printers = new List<DiscoveredPrinter>();

        public MainForm()
        {
            Text = "添加设备";
            Font = SystemFonts.MessageBoxFont;
            StartPosition = FormStartPosition.CenterScreen;
            FormBorderStyle = FormBorderStyle.FixedDialog;
            MaximizeBox = false;
            MinimizeBox = true;
            // 尺寸和比例参考 Windows 自带“添加设备”向导，这里整体再缩小一些
            ClientSize = new Size(600, 380);

            _titleLabel = new Label
            {
                AutoSize = true,
                Text = "选择要添加到这台电脑的设备或打印机",
                Font = new Font(SystemFonts.MessageBoxFont.FontFamily, 14f, FontStyle.Regular),
                ForeColor = Color.FromArgb(0, 114, 198),
                Location = new Point(20, 20)
            };

            _subtitleLabel = new Label
            {
                AutoSize = true,
                Text = "请选择要添加的打印机。",
                ForeColor = Color.FromArgb(96, 96, 96),
                Location = new Point(20, 55)
            };

            _refreshLinkLabel = new LinkLabel
            {
                AutoSize = true,
                Text = "刷新",
                Location = new Point(550, 55),
                Anchor = AnchorStyles.Top | AnchorStyles.Right,
                LinkBehavior = LinkBehavior.HoverUnderline
            };
            _refreshLinkLabel.LinkClicked += RefreshLinkLabel_LinkClicked;

            _printerListView = new ListView
            {
                Location = new Point(20, 85),
                Size = new Size(560, 220),
                View = View.Tile,
                MultiSelect = false,
                HideSelection = false,
                UseCompatibleStateImageBehavior = false,
                Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right
            };
            _printerListView.Columns.Add("设备", 240);
            _printerListView.Columns.Add("类型", 80);
            // 调整 Tile 宽度为 ListView 宽度的一半左右，以便一行显示两个设备
            _printerListView.TileSize = new Size(260, 56);

            _imageList = new ImageList
            {
                ImageSize = new Size(32, 32),
                ColorDepth = ColorDepth.Depth32Bit
            };
            _printerBitmap = LoadPrinterBitmap();
            _imageList.Images.Add(_printerBitmap ?? SystemIcons.Application.ToBitmap());
            _printerListView.LargeImageList = _imageList;

            _linkLabel = new LinkLabel
            {
                AutoSize = true,
                Text = "我所需的打印机未列出",
                Location = new Point(20, 345),
                Anchor = AnchorStyles.Bottom | AnchorStyles.Left,
                LinkBehavior = LinkBehavior.HoverUnderline
            };
            _linkLabel.LinkClicked += LinkLabel_LinkClicked;

            _progressBar = new ProgressBar
            {
                Location = new Point(20, 330),
                Size = new Size(560, 10),
                Style = ProgressBarStyle.Marquee,
                Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right
            };

            _nextButton = new Button
            {
                Text = "下一步(&N)",
                Anchor = AnchorStyles.Bottom | AnchorStyles.Right,
                Location = new Point(420, 345),
                Size = new Size(75, 25),
                Enabled = false
            };
            _nextButton.Click += NextButton_Click;

            _cancelButton = new Button
            {
                Text = "取消",
                Anchor = AnchorStyles.Bottom | AnchorStyles.Right,
                Location = new Point(505, 345),
                Size = new Size(65, 25)
            };
            _cancelButton.Click += (s, e) => Close();

            Controls.Add(_titleLabel);
            Controls.Add(_subtitleLabel);
            Controls.Add(_refreshLinkLabel);
            Controls.Add(_printerListView);
            Controls.Add(_progressBar);
            Controls.Add(_linkLabel);
            Controls.Add(_nextButton);
            Controls.Add(_cancelButton);

            Shown += MainForm_Shown;
        }

        private void MainForm_Shown(object sender, EventArgs e)
        {
            BeginSearch();
        }

        private void BeginSearch()
        {
            _printers.Clear();
            _printerListView.Items.Clear();
            _subtitleLabel.Text = "正在搜索设备";
            _progressBar.Style = ProgressBarStyle.Marquee;
            _nextButton.Enabled = false;

            // 后台线程执行发现逻辑，避免阻塞 UI
            System.Threading.Tasks.Task.Run(() =>
            {
                try
                {
                    var discovered = DiscoverPrinters();

                    Invoke((Action)(() =>
                    {
                        // 去重：基于打印机类型和标识符（IPP 使用 URI，TCP_RAW 使用 IP:Port）
                        var seenPrinters = new HashSet<string>();
                        var uniquePrinters = new List<DiscoveredPrinter>();
                        
                        foreach (var printer in discovered)
                        {
                            string key;
                            if (printer.PrinterType == "TCP_RAW")
                            {
                                // TCP/IP RAW 打印机：使用 IP:Port 作为唯一标识
                                key = $"TCP_RAW:{printer.TcpIp}:{printer.TcpPort}";
                            }
                            else
                            {
                                // IPP 打印机：使用 URI 作为唯一标识
                                key = $"IPP:{printer.Uri}";
                            }
                            
                            if (!seenPrinters.Contains(key))
                            {
                                seenPrinters.Add(key);
                                uniquePrinters.Add(printer);
                            }
                        }
                        
                        foreach (var printer in uniquePrinters)
                        {
                            _printers.Add(printer);
                            var friendlyName = RemoveQueueSuffix(printer.DisplayName);
                            var item = new ListViewItem(friendlyName, 0)
                            {
                                Tag = printer
                            };
                            // 显示打印机类型：IPP 或 TCP/IP RAW
                            var typeText = printer.PrinterType == "TCP_RAW" 
                                ? $"TCP/IP RAW ({printer.TcpIp}:{printer.TcpPort})" 
                                : "IPP";
                            item.SubItems.Add(typeText);
                            _printerListView.Items.Add(item);
                        }

                        if (_printers.Count == 0)
                        {
                            _subtitleLabel.Text = "未发现任何打印机。";
                        }
                        else
                        {
                            _subtitleLabel.Text = "请选择要添加的打印机。";
                            _nextButton.Enabled = true;
                        }

                        _progressBar.Style = ProgressBarStyle.Blocks;
                    }));
                }
                catch (Exception ex)
                {
                    Invoke((Action)(() =>
                    {
                        _subtitleLabel.Text = "搜索过程中出错。";
                        _progressBar.Style = ProgressBarStyle.Blocks;
                        MessageBox.Show(this, ex.Message, "搜索出错",
                            MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }));
                }
            });
        }

        private void RefreshLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            BeginSearch();
        }

        private void LinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            try
            {
                // 调用系统原生的“添加打印机”向导（/im 参数打开完整的添加打印机窗口）
                var psi = new ProcessStartInfo
                {
                    FileName = "rundll32.exe",
                    Arguments = "printui.dll,PrintUIEntry /im",
                    UseShellExecute = true
                };
                Process.Start(psi);
            }
            catch (Exception ex)
            {
                MessageBox.Show(this,
                    "无法打开系统添加打印机向导：\n" + ex.Message,
                    "错误",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }
        }

        private void NextButton_Click(object sender, EventArgs e)
        {
            if (_printerListView.SelectedItems.Count == 0)
            {
                MessageBox.Show(this, "请先选择一个要添加的打印机。", "提示",
                    MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            var printer = (DiscoveredPrinter)_printerListView.SelectedItems[0].Tag;
            if (printer == null)
            {
                return;
            }

            // 改为：调用系统“添加打印机”向导，并自动在“按名称选择共享打印机”页面填入 URI 并点击“下一步”
            _nextButton.Enabled = false;
            _subtitleLabel.Text = "正在打开系统添加打印机向导，请不要操作该向导窗口…";

            Task.Run(() =>
            {
                bool shouldClose = true;
                try
                {
                    if (printer.PrinterType == "TCP_RAW")
                    {
                        // 使用 Windows API 直接添加标准 TCP/IP 打印机
                        // TCP/IP 打印机的自动化流程较长，需要等待所有步骤完成
                        Invoke((Action)(() =>
                        {
                            _subtitleLabel.Text = "正在配置 TCP/IP 打印机，请稍候…";
                        }));
                        AddTcpIpPrinter(printer, (msg) =>
                        {
                            // 更新提示信息，让用户知道当前进度
                            Invoke((Action)(() =>
                            {
                                _subtitleLabel.Text = msg;
                            }));
                        });
                    }
                    else
                    {
                        // 使用 UI 自动化添加 IPP 打印机
                        // IPP 打印机流程较快，可以立即关闭
                        RunWizardAndAutoFill(printer.Uri);
                    }
                }
                catch (Exception ex)
                {
                    shouldClose = false; // 出错时不自动关闭，让用户看到错误信息
                    Invoke((Action)(() =>
                    {
                        MessageBox.Show(this,
                            "启动系统添加打印机向导失败：\n" + ex.Message,
                            "错误",
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Error);
                        _nextButton.Enabled = true;
                        _subtitleLabel.Text = "请选择一个打印机";
                    }));
                }
                finally
                {
                    if (shouldClose)
                    {
                        // 自动化流程完成后关闭当前窗口，后续流程由系统向导接管
                        Invoke((Action)(() =>
                        {
                            _subtitleLabel.Text = "自动化配置完成，窗口即将关闭…";
                        }));
                        Thread.Sleep(500); // 给用户一点时间看到提示
                        Invoke((Action)(Close));
                    }
                }
            });
        }

        /// <summary>
        /// 使用 Windows API 直接添加标准 TCP/IP 打印机
        /// </summary>
        private static void AddTcpIpPrinter(DiscoveredPrinter printer, Action<string> progressCallback = null)
        {
            try
            {
                // 使用和 IPP 相同的逻辑，直接打开 /im 页面（按名称或 TCP/IP 地址查找打印机）
                // 然后自动选择 TCP/IP 选项并填写 IP 地址和端口
                RunTcpIpWizardAndAutoFill(printer.TcpIp, printer.TcpPort, printer.DisplayName, progressCallback);
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException($"添加 TCP/IP 打印机失败：{ex.Message}", ex);
            }
        }
        
        /// <summary>
        /// 使用 UI 自动化填写 TCP/IP 打印机信息
        /// </summary>
        private static void RunTcpIpWizardAndAutoFill(string ip, int port, string printerName, Action<string> progressCallback = null)
        {
            // 使用和 IPP 相同的逻辑，直接打开 /im 页面（按名称或 TCP/IP 地址查找打印机）
            var psi = new ProcessStartInfo("rundll32.exe", "printui.dll,PrintUIEntry /im")
            {
                UseShellExecute = false
            };
            var proc = Process.Start(psi);
            if (proc == null)
            {
                throw new InvalidOperationException("无法启动系统添加打印机向导进程。");
            }

            // 等待"添加打印机"窗口出现（中文系统标题），并限制在刚启动的进程内
            AutomationElement mainWindow = null;
            for (var i = 0; i < 100; i++)
            {
                var condition = new AndCondition(
                    new PropertyCondition(AutomationElement.NameProperty, "添加打印机"),
                    new PropertyCondition(AutomationElement.ProcessIdProperty, proc.Id));

                mainWindow = AutomationElement.RootElement.FindFirst(TreeScope.Children, condition);

                if (mainWindow != null)
                {
                    break;
                }

                Thread.Sleep(200);
            }

            if (mainWindow == null)
            {
                throw new InvalidOperationException("未找到\"添加打印机\"窗口，请确认系统语言和界面是否匹配。");
            }

            // 将窗口置于前台，避免被其他窗口遮挡让用户误操作
            try
            {
                var hwnd = new IntPtr(mainWindow.Current.NativeWindowHandle);
                if (hwnd != IntPtr.Zero)
                {
                    ShowWindowAsync(hwnd, SW_SHOWNORMAL);
                    SetForegroundWindow(hwnd);
                }
            }
            catch
            {
                // 忽略前置失败，不影响后续 UIAutomation 操作
            }

            // 第一步：选择"使用 IP 地址或主机名添加打印机"单选按钮
            var tcpIpRadio = mainWindow.FindFirst(
                TreeScope.Descendants,
                new AndCondition(
                    new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.RadioButton),
                    new PropertyCondition(AutomationElement.NameProperty, "使用 IP 地址或主机名添加打印机(I)")));

            if (tcpIpRadio == null)
            {
                // 尝试其他可能的名称
                tcpIpRadio = mainWindow.FindFirst(
                    TreeScope.Descendants,
                    new AndCondition(
                        new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.RadioButton),
                        new PropertyCondition(AutomationElement.NameProperty, "使用 IP 地址或主机名添加打印机")));
            }

            if (tcpIpRadio == null)
            {
                throw new InvalidOperationException("未找到\"使用 IP 地址或主机名添加打印机\"单选按钮。");
            }

            // 等待单选按钮可用
            for (var i = 0; i < 20; i++)
            {
                var enabled = (bool)tcpIpRadio.GetCurrentPropertyValue(AutomationElement.IsEnabledProperty);
                if (enabled)
                {
                    break;
                }
                Thread.Sleep(200);
            }

            var selectionPattern = tcpIpRadio.GetCurrentPattern(SelectionItemPattern.Pattern) as SelectionItemPattern;
            if (selectionPattern == null)
            {
                throw new InvalidOperationException("无法访问单选按钮的 SelectionItemPattern。");
            }

            selectionPattern.Select();
            Thread.Sleep(500);

            // 点击"下一步"按钮，进入配置页面
            var nextButton = mainWindow.FindFirst(
                TreeScope.Descendants,
                new AndCondition(
                    new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button),
                    new PropertyCondition(AutomationElement.NameProperty, "下一步(N)")));

            if (nextButton == null)
            {
                throw new InvalidOperationException("未找到\"下一步(N)\"按钮。");
            }

            // 等待按钮可用
            for (var i = 0; i < 20; i++)
            {
                var enabled = (bool)nextButton.GetCurrentPropertyValue(AutomationElement.IsEnabledProperty);
                if (enabled)
                {
                    break;
                }
                Thread.Sleep(200);
            }

            if (!(bool)nextButton.GetCurrentPropertyValue(AutomationElement.IsEnabledProperty))
            {
                throw new InvalidOperationException("\"下一步(N)\"按钮未处于可用状态，无法点击。");
            }

            var nextInvokePattern = nextButton.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
            if (nextInvokePattern == null)
            {
                throw new InvalidOperationException("无法访问按钮的 InvokePattern。");
            }

            nextInvokePattern.Invoke();
            Thread.Sleep(1000);

            // 第二步：等待新窗口出现（TCP/IP 配置页面）
            AutomationElement configWindow = null;
            for (var i = 0; i < 50; i++)
            {
                var condition = new AndCondition(
                    new PropertyCondition(AutomationElement.NameProperty, "添加打印机"),
                    new PropertyCondition(AutomationElement.ProcessIdProperty, proc.Id));

                configWindow = AutomationElement.RootElement.FindFirst(TreeScope.Children, condition);

                if (configWindow != null)
                {
                    // 检查是否有"设备类型"下拉框（配置页面的特征）
                    var tempDeviceTypeCombo = configWindow.FindFirst(
                        TreeScope.Descendants,
                        new AndCondition(
                            new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ComboBox),
                            new PropertyCondition(AutomationElement.NameProperty, "设备类型(T):")));

                    if (tempDeviceTypeCombo != null)
                    {
                        break; // 找到了配置页面
                    }
                }
                Thread.Sleep(200);
            }

            if (configWindow == null)
            {
                throw new InvalidOperationException("未找到 TCP/IP 配置窗口。");
            }

            // 将配置窗口置于前台
            try
            {
                var hwnd = new IntPtr(configWindow.Current.NativeWindowHandle);
                if (hwnd != IntPtr.Zero)
                {
                    ShowWindowAsync(hwnd, SW_SHOWNORMAL);
                    SetForegroundWindow(hwnd);
                }
            }
            catch
            {
                // 忽略前置失败
            }

            Thread.Sleep(500);

            // 第三步：在下拉框中选择"TCP/IP 设备"
            var deviceTypeCombo = configWindow.FindFirst(
                TreeScope.Descendants,
                new AndCondition(
                    new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ComboBox),
                    new PropertyCondition(AutomationElement.NameProperty, "设备类型(T):")));

            if (deviceTypeCombo == null)
            {
                // 尝试其他可能的名称
                deviceTypeCombo = configWindow.FindFirst(
                    TreeScope.Descendants,
                    new AndCondition(
                        new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ComboBox),
                        new PropertyCondition(AutomationElement.NameProperty, "设备类型")));
            }

            if (deviceTypeCombo != null)
            {
                // 展开下拉框
                var expandCollapsePattern = deviceTypeCombo.GetCurrentPattern(ExpandCollapsePattern.Pattern) as ExpandCollapsePattern;
                if (expandCollapsePattern != null)
                {
                    expandCollapsePattern.Expand();
                    Thread.Sleep(300);

                    // 查找并选择"TCP/IP 设备"选项
                    var tcpIpOption = configWindow.FindFirst(
                        TreeScope.Descendants,
                        new PropertyCondition(AutomationElement.NameProperty, "TCP/IP 设备"));

                    if (tcpIpOption != null)
                    {
                        var selectionItemPattern = tcpIpOption.GetCurrentPattern(SelectionItemPattern.Pattern) as SelectionItemPattern;
                        selectionItemPattern?.Select();
                        Thread.Sleep(300);
                    }
                }
            }

            // 第四步：填写 IP 地址
            AutomationElement ipTextBox = null;
            for (var i = 0; i < 20; i++)
            {
                ipTextBox = configWindow.FindFirst(
                    TreeScope.Descendants,
                    new AndCondition(
                        new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit),
                        new PropertyCondition(AutomationElement.NameProperty, "主机名或 IP 地址(A):")));

                if (ipTextBox == null)
                {
                    ipTextBox = configWindow.FindFirst(
                        TreeScope.Descendants,
                        new AndCondition(
                            new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit),
                            new PropertyCondition(AutomationElement.NameProperty, "主机名或 IP 地址")));
                }

                if (ipTextBox != null)
                {
                    var enabled = (bool)ipTextBox.GetCurrentPropertyValue(AutomationElement.IsEnabledProperty);
                    if (enabled)
                    {
                        break;
                    }
                }
                Thread.Sleep(200);
            }

            if (ipTextBox == null)
            {
                throw new InvalidOperationException("未找到 IP 地址输入框。");
            }

            if (!(bool)ipTextBox.GetCurrentPropertyValue(AutomationElement.IsEnabledProperty))
            {
                throw new InvalidOperationException("IP 地址输入框未处于可用状态，无法填写。");
            }

            var ipValuePattern = ipTextBox.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
            if (ipValuePattern == null)
            {
                throw new InvalidOperationException("无法访问 IP 地址输入框的 ValuePattern。");
            }

            ipValuePattern.SetValue(ip);
            Thread.Sleep(300);

            // 第五步：填写端口名称（可选）
            var portTextBox = configWindow.FindFirst(
                TreeScope.Descendants,
                new AndCondition(
                    new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit),
                    new PropertyCondition(AutomationElement.NameProperty, "端口名称(P):")));

            if (portTextBox == null)
            {
                portTextBox = configWindow.FindFirst(
                    TreeScope.Descendants,
                    new AndCondition(
                        new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit),
                        new PropertyCondition(AutomationElement.NameProperty, "端口名称")));
            }

            if (portTextBox == null)
            {
                portTextBox = configWindow.FindFirst(
                    TreeScope.Descendants,
                    new AndCondition(
                        new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit),
                        new PropertyCondition(AutomationElement.NameProperty, "端口名(P):")));
            }

            if (portTextBox == null)
            {
                portTextBox = configWindow.FindFirst(
                    TreeScope.Descendants,
                    new AndCondition(
                        new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit),
                        new PropertyCondition(AutomationElement.NameProperty, "端口名")));
            }

            if (portTextBox != null)
            {
                var portValuePattern = portTextBox.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
                if (portValuePattern != null)
                {
                    var portName = $"IP_{ip}";
                    portValuePattern.SetValue(portName);
                    Thread.Sleep(300);
                }
            }

            // 第六步：点击"下一步"继续
            var configNextButton = configWindow.FindFirst(
                TreeScope.Descendants,
                new AndCondition(
                    new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button),
                    new PropertyCondition(AutomationElement.NameProperty, "下一步(N)")));

            if (configNextButton == null)
            {
                throw new InvalidOperationException("未找到配置页面的\"下一步(N)\"按钮。");
            }

            // 等待按钮可用
            for (var i = 0; i < 20; i++)
            {
                var enabled = (bool)configNextButton.GetCurrentPropertyValue(AutomationElement.IsEnabledProperty);
                if (enabled)
                {
                    break;
                }
                Thread.Sleep(200);
            }

            if (!(bool)configNextButton.GetCurrentPropertyValue(AutomationElement.IsEnabledProperty))
            {
                throw new InvalidOperationException("配置页面的\"下一步(N)\"按钮未处于可用状态，无法点击。");
            }

            var configNextInvokePattern = configNextButton.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
            if (configNextInvokePattern == null)
            {
                throw new InvalidOperationException("无法访问配置页面按钮的 InvokePattern。");
            }

            configNextInvokePattern.Invoke();
            Thread.Sleep(1000);

            // 第六步半：等待"检测 TCP/IP 端口"完成
            // 点击"下一步"后，可能会先出现"检测 TCP/IP 端口"窗口，需要等待检测完成
            progressCallback?.Invoke("正在检测 TCP/IP 端口，请稍候…");
            
            AutomationElement detectingWindow = null;
            for (var i = 0; i < 30; i++)
            {
                var condition = new AndCondition(
                    new PropertyCondition(AutomationElement.NameProperty, "添加打印机"),
                    new PropertyCondition(AutomationElement.ProcessIdProperty, proc.Id));

                detectingWindow = AutomationElement.RootElement.FindFirst(TreeScope.Children, condition);

                if (detectingWindow != null)
                {
                    // 检查是否有"检测 TCP/IP 端口"的文本（检测窗口的特征）
                    var detectingText = detectingWindow.FindFirst(
                        TreeScope.Descendants,
                        new PropertyCondition(AutomationElement.NameProperty, "检测 TCP/IP 端口"));

                    if (detectingText != null)
                    {
                        // 找到了检测窗口，等待检测完成
                        // 检测完成后，"下一步"按钮会变为可用，或者窗口会切换到下一个页面
                        for (var j = 0; j < 200; j++) // 最多等待 40 秒
                        {
                            Thread.Sleep(200);

                            // 检查"下一步"按钮是否可用（检测完成的标志）
                            var nextBtn = detectingWindow.FindFirst(
                                TreeScope.Descendants,
                                new AndCondition(
                                    new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button),
                                    new PropertyCondition(AutomationElement.NameProperty, "下一步(N)")));

                            if (nextBtn != null)
                            {
                                var enabled = (bool)nextBtn.GetCurrentPropertyValue(AutomationElement.IsEnabledProperty);
                                if (enabled)
                                {
                                    // 检测完成，"下一步"按钮已可用
                                    progressCallback?.Invoke("端口检测完成，继续配置…");
                                    break;
                                }
                            }

                            // 或者检查是否已经切换到下一个页面（有"自定义"单选按钮）
                            var customRadio = detectingWindow.FindFirst(
                                TreeScope.Descendants,
                                new AndCondition(
                                    new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.RadioButton),
                                    new PropertyCondition(AutomationElement.NameProperty, "自定义(C)")));

                            if (customRadio != null)
                            {
                                // 已经切换到下一个页面，检测完成
                                progressCallback?.Invoke("端口检测完成，继续配置…");
                                break;
                            }
                        }
                        break;
                    }
                }
                Thread.Sleep(200);
            }

            // 第七步：处理"需要额外端口信息"窗口
            // 等待新窗口出现（端口配置页面）
            AutomationElement portConfigWindow = null;
            for (var i = 0; i < 50; i++)
            {
                var condition = new AndCondition(
                    new PropertyCondition(AutomationElement.NameProperty, "添加打印机"),
                    new PropertyCondition(AutomationElement.ProcessIdProperty, proc.Id));

                portConfigWindow = AutomationElement.RootElement.FindFirst(TreeScope.Children, condition);

                if (portConfigWindow != null)
                {
                    // 检查是否有"自定义"单选按钮（端口配置页面的特征）
                    var customRadio = portConfigWindow.FindFirst(
                        TreeScope.Descendants,
                        new AndCondition(
                            new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.RadioButton),
                            new PropertyCondition(AutomationElement.NameProperty, "自定义(C)")));

                    if (customRadio != null)
                    {
                        break; // 找到了端口配置页面
                    }
                }
                Thread.Sleep(200);
            }

            if (portConfigWindow != null)
            {
                // 将窗口置于前台
                try
                {
                    var hwnd = new IntPtr(portConfigWindow.Current.NativeWindowHandle);
                    if (hwnd != IntPtr.Zero)
                    {
                        ShowWindowAsync(hwnd, SW_SHOWNORMAL);
                        SetForegroundWindow(hwnd);
                    }
                }
                catch
                {
                    // 忽略前置失败
                }

                Thread.Sleep(500);

                // 选择"自定义"单选按钮
                var customRadio = portConfigWindow.FindFirst(
                    TreeScope.Descendants,
                    new AndCondition(
                        new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.RadioButton),
                        new PropertyCondition(AutomationElement.NameProperty, "自定义(C)")));

                if (customRadio == null)
                {
                    customRadio = portConfigWindow.FindFirst(
                        TreeScope.Descendants,
                        new AndCondition(
                            new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.RadioButton),
                            new PropertyCondition(AutomationElement.NameProperty, "自定义")));
                }

                if (customRadio != null)
                {
                    var customSelectionPattern = customRadio.GetCurrentPattern(SelectionItemPattern.Pattern) as SelectionItemPattern;
                    customSelectionPattern?.Select();
                    Thread.Sleep(300);

                    // 查找并点击"设置"按钮
                    var settingsButton = portConfigWindow.FindFirst(
                        TreeScope.Descendants,
                        new AndCondition(
                            new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button),
                            new PropertyCondition(AutomationElement.NameProperty, "设置(E)...")));

                    if (settingsButton == null)
                    {
                        settingsButton = portConfigWindow.FindFirst(
                            TreeScope.Descendants,
                            new AndCondition(
                                new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button),
                                new PropertyCondition(AutomationElement.NameProperty, "设置...")));
                    }

                    if (settingsButton == null)
                    {
                        settingsButton = portConfigWindow.FindFirst(
                            TreeScope.Descendants,
                            new AndCondition(
                                new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button),
                                new PropertyCondition(AutomationElement.NameProperty, "设置")));
                    }

                    if (settingsButton != null)
                    {
                        var settingsInvokePattern = settingsButton.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
                        if (settingsInvokePattern != null)
                        {
                            settingsInvokePattern.Invoke();
                            Thread.Sleep(1000);

                            // 第八步：处理"配置标准的TCP/IP 端口监视器"对话框
                            progressCallback?.Invoke("正在打开端口监视器设置…");

                            AutomationElement monitorDialog = null;
                            for (var j = 0; j < 120; j++)
                            {
                                monitorDialog = FindWindowByNameKeywords(proc.Id, false, "TCP/IP", "端口监视器");
                                if (monitorDialog == null)
                                {
                                    // 兼容英文系统或其他语言
                                    monitorDialog = FindWindowByNameKeywords(proc.Id, false, "Configure", "TCP/IP");
                                }

                                if (monitorDialog != null)
                                {
                                    // 确认窗口上已经出现端口文本框，确保对话框已经初始化完毕
                                    var textboxCheck = monitorDialog.FindFirst(
                                        TreeScope.Descendants,
                                        new AndCondition(
                                            new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit),
                                            new PropertyCondition(AutomationElement.NameProperty, "端口号(N):")));

                                    if (textboxCheck == null)
                                    {
                                        textboxCheck = monitorDialog.FindFirst(
                                            TreeScope.Descendants,
                                            new AndCondition(
                                                new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit),
                                                new PropertyCondition(AutomationElement.NameProperty, "端口号")));
                                    }

                                    if (textboxCheck != null)
                                    {
                                        break;
                                    }
                                }

                                Thread.Sleep(250);
                            }

                            if (monitorDialog != null)
                            {
                                // 将对话框置于前台
                                try
                                {
                                    var hwnd = new IntPtr(monitorDialog.Current.NativeWindowHandle);
                                    if (hwnd != IntPtr.Zero)
                                    {
                                        ShowWindowAsync(hwnd, SW_SHOWNORMAL);
                                        SetForegroundWindow(hwnd);
                                    }
                                }
                                catch
                                {
                                    // 忽略前置失败
                                }

                                Thread.Sleep(500);

                                // 选择"Raw"协议单选按钮
                                var rawRadio = monitorDialog.FindFirst(
                                    TreeScope.Descendants,
                                    new AndCondition(
                                        new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.RadioButton),
                                        new PropertyCondition(AutomationElement.NameProperty, "Raw(R)")));

                                if (rawRadio == null)
                                {
                                    rawRadio = monitorDialog.FindFirst(
                                        TreeScope.Descendants,
                                        new AndCondition(
                                            new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.RadioButton),
                                            new PropertyCondition(AutomationElement.NameProperty, "Raw")));
                                }

                                if (rawRadio != null)
                                {
                                    var rawSelectionPattern = rawRadio.GetCurrentPattern(SelectionItemPattern.Pattern) as SelectionItemPattern;
                                    rawSelectionPattern?.Select();
                                    Thread.Sleep(300);
                                }

                                // 填写端口号
                                var portNumberTextBox = monitorDialog.FindFirst(
                                    TreeScope.Descendants,
                                    new AndCondition(
                                        new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit),
                                        new PropertyCondition(AutomationElement.NameProperty, "端口号(N):")));

                                if (portNumberTextBox == null)
                                {
                                    portNumberTextBox = monitorDialog.FindFirst(
                                        TreeScope.Descendants,
                                        new AndCondition(
                                            new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit),
                                            new PropertyCondition(AutomationElement.NameProperty, "端口号")));
                                }

                                if (portNumberTextBox != null)
                                {
                                    // 等待输入框可用
                                    for (var k = 0; k < 10; k++)
                                    {
                                        var enabled = (bool)portNumberTextBox.GetCurrentPropertyValue(AutomationElement.IsEnabledProperty);
                                        if (enabled)
                                        {
                                            break;
                                        }
                                        Thread.Sleep(200);
                                    }

                                    var portValuePattern = portNumberTextBox.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
                                    if (portValuePattern != null)
                                    {
                                        progressCallback?.Invoke($"正在设置端口号 {port} …");
                                        portValuePattern.SetValue(port.ToString());
                                        Thread.Sleep(300);
                                    }
                                }

                                // 点击"确定"按钮
                                var okButton = monitorDialog.FindFirst(
                                    TreeScope.Descendants,
                                    new AndCondition(
                                        new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button),
                                        new PropertyCondition(AutomationElement.NameProperty, "确定")));

                                if (okButton != null)
                                {
                                    var okInvokePattern = okButton.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
                                    okInvokePattern?.Invoke();
                                    Thread.Sleep(500);
                                    progressCallback?.Invoke("端口监视器设置完成，返回上一步…");
                                }
                            }
                        }
                    }

                    // 第九步：回到主窗口，点击"下一步"
                    Thread.Sleep(500);
                    var portConfigNextButton = portConfigWindow.FindFirst(
                        TreeScope.Descendants,
                        new AndCondition(
                            new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button),
                            new PropertyCondition(AutomationElement.NameProperty, "下一步(N)")));

                    if (portConfigNextButton != null)
                    {
                        // 等待按钮可用
                        for (var i = 0; i < 20; i++)
                        {
                            var enabled = (bool)portConfigNextButton.GetCurrentPropertyValue(AutomationElement.IsEnabledProperty);
                            if (enabled)
                            {
                                break;
                            }
                            Thread.Sleep(200);
                        }

                        var portConfigNextInvokePattern = portConfigNextButton.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
                        if (portConfigNextInvokePattern != null)
                        {
                            portConfigNextInvokePattern.Invoke();
                            Thread.Sleep(1000);
                            progressCallback?.Invoke("端口配置完成，正在进入驱动选择…");
                        }
                    }
                }
            }

            // 自动化流程到此结束，后续的驱动选择等步骤需要用户手动完成
            // 注意：窗口会在自动化完成后自动关闭
        }

        private static AutomationElement FindWindowByNameKeywords(int processId, bool strictProcessMatch = true, params string[] keywords)
        {
            Condition baseCondition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window);
            if (strictProcessMatch && processId > 0)
            {
                baseCondition = new AndCondition(
                    baseCondition,
                    new PropertyCondition(AutomationElement.ProcessIdProperty, processId));
            }

            var windows = AutomationElement.RootElement.FindAll(TreeScope.Children, baseCondition);
            foreach (AutomationElement window in windows)
            {
                if (!strictProcessMatch && processId > 0)
                {
                    try
                    {
                        var winProcessId = window.Current.ProcessId;
                        if (winProcessId != processId)
                        {
                            // 当不强制匹配进程时，仍然更倾向于指定进程；
                            // 若不是同进程，则延后处理
                            continue;
                        }
                    }
                    catch
                    {
                        // ignore
                    }
                }

                string name;
                try
                {
                    name = window.Current.Name ?? string.Empty;
                }
                catch
                {
                    continue;
                }

                bool matched = true;
                foreach (var keyword in keywords)
                {
                    if (string.IsNullOrEmpty(keyword))
                    {
                        continue;
                    }

                    if (name.IndexOf(keyword, StringComparison.OrdinalIgnoreCase) < 0)
                    {
                        matched = false;
                        break;
                    }
                }

                if (matched)
                {
                    return window;
                }
            }

            if (!strictProcessMatch && processId > 0)
            {
                // 再次遍历所有窗口（不区分进程），防止因跳过非匹配进程窗口而找不到
                windows = AutomationElement.RootElement.FindAll(TreeScope.Children,
                    new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window));

                foreach (AutomationElement window in windows)
                {
                    string name;
                    try
                    {
                        name = window.Current.Name ?? string.Empty;
                    }
                    catch
                    {
                        continue;
                    }

                    bool matched = true;
                    foreach (var keyword in keywords)
                    {
                        if (string.IsNullOrEmpty(keyword))
                        {
                            continue;
                        }

                        if (name.IndexOf(keyword, StringComparison.OrdinalIgnoreCase) < 0)
                        {
                            matched = false;
                            break;
                        }
                    }

                    if (matched)
                    {
                        return window;
                    }
                }
            }

            return null;
        }

        private static void RunWizardAndAutoFill(string ippUri)
        {
            // 仅在 Windows 10/11 测试通过：使用 /im 直接打开“按名称或 TCP/IP 地址查找打印机”页面
            var psi = new ProcessStartInfo("rundll32.exe", "printui.dll,PrintUIEntry /im")
            {
                UseShellExecute = false
            };
            var proc = Process.Start(psi);
                    if (proc == null)
                    {
                throw new InvalidOperationException("无法启动系统添加打印机向导进程。");
            }

            // 等待“添加打印机”窗口出现（中文系统标题），并限制在刚启动的进程内
            AutomationElement mainWindow = null;
            for (var i = 0; i < 100; i++)
            {
                var condition = new AndCondition(
                    new PropertyCondition(AutomationElement.NameProperty, "添加打印机"),
                    new PropertyCondition(AutomationElement.ProcessIdProperty, proc.Id));

                mainWindow = AutomationElement.RootElement.FindFirst(TreeScope.Children, condition);

                if (mainWindow != null)
                {
                    break;
                }

                Thread.Sleep(200);
            }

            if (mainWindow == null)
            {
                throw new InvalidOperationException("未找到\"添加打印机\"窗口，请确认系统语言和界面是否匹配。");
            }

            // 将窗口置于前台，避免被其他窗口遮挡让用户误操作
            try
            {
                var hwnd = new IntPtr(mainWindow.Current.NativeWindowHandle);
                if (hwnd != IntPtr.Zero)
                {
                    ShowWindowAsync(hwnd, SW_SHOWNORMAL);
                    SetForegroundWindow(hwnd);
                }
            }
            catch
            {
                // 忽略前置失败，不影响后续 UIAutomation 操作
            }

            // 选择“按名称选择共享打印机”单选框，使下面的编辑框和“下一步”按钮变为可用
            var radioButtons = mainWindow.FindAll(
                TreeScope.Descendants,
                new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.RadioButton));

            if (radioButtons == null || radioButtons.Count < 2)
            {
                throw new InvalidOperationException("未找到“按名称选择共享打印机”选项。");
            }

            var shareByNameRadio = radioButtons[1];
            var radioSelectPattern = shareByNameRadio.GetCurrentPattern(SelectionItemPattern.Pattern) as SelectionItemPattern;
            if (radioSelectPattern != null)
            {
                radioSelectPattern.Select();
            }
            else
            {
                var radioInvokePattern = shareByNameRadio.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
                if (radioInvokePattern != null)
                {
                    radioInvokePattern.Invoke();
                }
            }

            Thread.Sleep(500);

            // 查找第一个编辑框并填入 IPP URI
            var edit = mainWindow.FindFirst(
                TreeScope.Descendants,
                new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit));

            if (edit == null)
            {
                throw new InvalidOperationException("未找到 URI 输入编辑框。");
            }

            for (var i = 0; i < 20; i++)
            {
                var enabled = (bool)edit.GetCurrentPropertyValue(AutomationElement.IsEnabledProperty);
                if (enabled)
                {
                    break;
                }
                Thread.Sleep(200);
            }

            if (!(bool)edit.GetCurrentPropertyValue(AutomationElement.IsEnabledProperty))
            {
                throw new InvalidOperationException("URI 输入编辑框未处于可用状态，无法填写。");
            }

            var vp = edit.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
            if (vp == null)
            {
                throw new InvalidOperationException("无法访问编辑框的 ValuePattern。");
            }

            vp.SetValue(ippUri);

            // 找到“下一步(N)”按钮并点击
            var nextButton = mainWindow.FindFirst(
                TreeScope.Descendants,
                new AndCondition(
                    new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button),
                    new PropertyCondition(AutomationElement.NameProperty, "下一步(N)")));

            if (nextButton == null)
            {
                throw new InvalidOperationException("未找到\"下一步(N)\"按钮。");
            }

            for (var i = 0; i < 20; i++)
            {
                var enabled = (bool)nextButton.GetCurrentPropertyValue(AutomationElement.IsEnabledProperty);
                if (enabled)
                {
                    break;
                }
                Thread.Sleep(200);
            }

            if (!(bool)nextButton.GetCurrentPropertyValue(AutomationElement.IsEnabledProperty))
            {
                throw new InvalidOperationException("\"下一步(N)\"按钮未处于可用状态，无法点击。");
            }

            var ip = nextButton.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
            if (ip == null)
            {
                throw new InvalidOperationException("无法访问按钮的 InvokePattern。");
            }

            ip.Invoke();
        }

        private static List<DiscoveredPrinter> DiscoverPrinters()
        {
            var result = new List<DiscoveredPrinter>();
            // 用于去重的 HashSet，基于打印机的唯一标识符
            var seenKeys = new HashSet<string>();
            
            // 获取客户机的本地IP地址和网段信息
            var localNetworks = GetLocalNetworks();

            using (var udp = new UdpClient())
            {
                udp.EnableBroadcast = true;

                byte[] requestBytes = Encoding.UTF8.GetBytes(RequestMagic);
                var targets = new List<IPEndPoint>();
                targets.AddRange(GetBroadcastEndpoints(ServerPort));
                if (targets.Count == 0)
                {
                    targets.Add(new IPEndPoint(IPAddress.Broadcast, ServerPort));
                }

                foreach (var target in targets)
                {
                    udp.Send(requestBytes, requestBytes.Length, target);
                }

                udp.Client.ReceiveTimeout = 3000;

                var endTime = DateTime.UtcNow.AddMilliseconds(3000);
                while (DateTime.UtcNow < endTime)
                {
                    try
                    {
                        IPEndPoint remoteEp = new IPEndPoint(IPAddress.Any, 0);
                        byte[] data = udp.Receive(ref remoteEp);
                        string text = Encoding.UTF8.GetString(data ?? new byte[0]);

                        var printers = ParseResponse(text, localNetworks);
                        if (printers != null && printers.Count > 0)
                        {
                            foreach (var printer in printers)
                            {
                                // 生成唯一标识符
                                string key;
                                if (printer.PrinterType == "TCP_RAW")
                                {
                                    // TCP/IP RAW 打印机：使用 IP:Port 作为唯一标识
                                    key = $"TCP_RAW:{printer.TcpIp}:{printer.TcpPort}";
                                }
                                else
                                {
                                    // IPP 打印机：使用 URI 作为唯一标识
                                    key = $"IPP:{printer.Uri}";
                                }
                                
                                // 只添加未出现过的打印机
                                if (!seenKeys.Contains(key))
                                {
                                    seenKeys.Add(key);
                                    result.Add(printer);
                                }
                            }
                        }
                    }
                    catch (SocketException sex)
                    {
                        if (sex.SocketErrorCode == SocketError.TimedOut)
                        {
                            break;
                        }
                        break;
                    }
                }
            }

            return result;
        }
        
        /// <summary>
        /// 本地网络信息（IP地址和子网掩码）
        /// </summary>
        private class LocalNetworkInfo
        {
            public IPAddress Address { get; set; }
            public IPAddress SubnetMask { get; set; }
        }
        
        /// <summary>
        /// 获取客户机的本地网络信息（IP地址和子网掩码）
        /// </summary>
        private static List<LocalNetworkInfo> GetLocalNetworks()
        {
            var networks = new List<LocalNetworkInfo>();
            
            try
            {
                var nics = NetworkInterface.GetAllNetworkInterfaces();
                foreach (var nic in nics)
                {
                    if (nic.OperationalStatus != OperationalStatus.Up)
                        continue;

                    if (nic.NetworkInterfaceType == NetworkInterfaceType.Loopback ||
                        nic.NetworkInterfaceType == NetworkInterfaceType.Tunnel)
                        continue;

                    var ipProps = nic.GetIPProperties();
                    foreach (var ua in ipProps.UnicastAddresses)
                    {
                        if (ua.Address.AddressFamily != AddressFamily.InterNetwork)
                            continue;
                        
                        if (ua.IPv4Mask != null)
                        {
                            networks.Add(new LocalNetworkInfo
                            {
                                Address = ua.Address,
                                SubnetMask = ua.IPv4Mask
                            });
                        }
                    }
                }
            }
            catch
            {
                // 忽略错误
            }
            
            return networks;
        }
        
        /// <summary>
        /// 检查IP地址是否与客户机在同一网段
        /// </summary>
        private static bool IsInSameNetwork(IPAddress remoteIp, List<LocalNetworkInfo> localNetworks)
        {
            if (remoteIp == null || localNetworks == null || localNetworks.Count == 0)
            {
                return false;
            }
            
            try
            {
                var remoteBytes = remoteIp.GetAddressBytes();
                if (remoteBytes.Length != 4)
                {
                    return false;
                }
                
                foreach (var networkInfo in localNetworks)
                {
                    var localBytes = networkInfo.Address.GetAddressBytes();
                    var maskBytes = networkInfo.SubnetMask.GetAddressBytes();
                    
                    if (localBytes.Length != 4 || maskBytes.Length != 4)
                    {
                        continue;
                    }
                    
                    // 计算网络地址：IP & 子网掩码
                    var localNetwork = new byte[4];
                    var remoteNetwork = new byte[4];
                    
                    for (int i = 0; i < 4; i++)
                    {
                        localNetwork[i] = (byte)(localBytes[i] & maskBytes[i]);
                        remoteNetwork[i] = (byte)(remoteBytes[i] & maskBytes[i]);
                    }
                    
                    // 比较网络地址是否相同
                    if (localNetwork[0] == remoteNetwork[0] &&
                        localNetwork[1] == remoteNetwork[1] &&
                        localNetwork[2] == remoteNetwork[2] &&
                        localNetwork[3] == remoteNetwork[3])
                    {
                        return true;
                    }
                }
            }
            catch
            {
                // 忽略错误
            }
            
            return false;
        }

        private static List<IPEndPoint> GetBroadcastEndpoints(int port)
        {
            var list = new List<IPEndPoint>();
            var seen = new HashSet<string>();

            try
            {
                var nics = NetworkInterface.GetAllNetworkInterfaces();
                foreach (var nic in nics)
                {
                    if (nic.OperationalStatus != OperationalStatus.Up)
                        continue;

                    if (nic.NetworkInterfaceType == NetworkInterfaceType.Loopback ||
                        nic.NetworkInterfaceType == NetworkInterfaceType.Tunnel)
                        continue;

                    var ipProps = nic.GetIPProperties();
                    foreach (var ua in ipProps.UnicastAddresses)
                    {
                        if (ua.Address.AddressFamily != AddressFamily.InterNetwork)
                            continue;
                        if (ua.IPv4Mask == null)
                            continue;

                        var ipBytes = ua.Address.GetAddressBytes();
                        var maskBytes = ua.IPv4Mask.GetAddressBytes();
                        if (ipBytes.Length != 4 || maskBytes.Length != 4)
                            continue;

                        var broadcastBytes = new byte[4];
                        for (int i = 0; i < 4; i++)
                        {
                            broadcastBytes[i] = (byte)(ipBytes[i] | (~maskBytes[i]));
                        }

                        var key = broadcastBytes[0] + "." + broadcastBytes[1] + "." + broadcastBytes[2] + "." + broadcastBytes[3];
                        if (seen.Add(key))
                        {
                            list.Add(new IPEndPoint(new IPAddress(broadcastBytes), port));
                        }
                    }
                }
            }
            catch
            {
            }

            return list;
        }

        private static List<DiscoveredPrinter> ParseResponse(string resp, List<LocalNetworkInfo> localNetworks = null)
        {
            var list = new List<DiscoveredPrinter>();

            if (string.IsNullOrEmpty(resp))
                return list;

            if (!resp.StartsWith("IPP_SERVER|", StringComparison.OrdinalIgnoreCase))
            {
                return list;
            }

            string body = resp.Substring("IPP_SERVER|".Length);
            string[] parts = body.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

            string serverName = "";
            string ip = "";
            string port = "";
            string printersRaw = "";
            string tcpPrintersRaw = "";

            foreach (var part in parts)
            {
                int idx = part.IndexOf('=');
                if (idx <= 0) continue;

                string key = part.Substring(0, idx);
                string value = part.Substring(idx + 1);

                switch (key)
                {
                    case "Name":
                        serverName = value;
                        break;
                    case "IP":
                        ip = value;
                        break;
                    case "Port":
                        port = value;
                        break;
                    case "Printers":
                        printersRaw = value;
                        break;
                    case "TcpPrinters":
                        tcpPrintersRaw = value;
                        break;
                }
            }
            
            // 检查服务端的IP地址是否与客户机在同一网段
            if (!string.IsNullOrEmpty(ip) && localNetworks != null && localNetworks.Count > 0)
            {
                if (IPAddress.TryParse(ip, out var serverIp))
                {
                    if (!IsInSameNetwork(serverIp, localNetworks))
                    {
                        // 服务端IP不在同一网段，忽略此响应
                        return list;
                    }
                }
            }

            // 解析 IPP 打印机
            if (!string.IsNullOrEmpty(printersRaw))
            {
                string[] printerItems = printersRaw.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var item in printerItems)
                {
                    string[] kv = item.Split(new[] { ',' }, 2);
                    string pName = kv.Length > 0 ? kv[0] : "";
                    string pUri = kv.Length > 1 ? kv[1] : "";

                    if (string.IsNullOrWhiteSpace(pUri))
                    {
                        continue;
                    }

                    list.Add(new DiscoveredPrinter
                    {
                        ServerName = serverName,
                        ServerIp = ip,
                        Port = port,
                        DisplayName = pName,
                        Uri = pUri,
                        PrinterType = "IPP"
                    });
                }
            }

            // 解析 TCP/IP RAW 打印机
            if (!string.IsNullOrEmpty(tcpPrintersRaw))
            {
                string[] tcpPrinterItems = tcpPrintersRaw.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var item in tcpPrinterItems)
                {
                    string[] kv = item.Split(new[] { ',' }, 2);
                    string pName = kv.Length > 0 ? kv[0] : "";
                    string ipPort = kv.Length > 1 ? kv[1] : "";

                    if (string.IsNullOrWhiteSpace(ipPort))
                    {
                        continue;
                    }

                    // 解析 IP:端口 格式
                    string[] ipPortParts = ipPort.Split(new[] { ':' }, 2);
                    string tcpIp = ipPortParts.Length > 0 ? ipPortParts[0] : "";
                    int tcpPort = 9100;
                    if (ipPortParts.Length > 1 && int.TryParse(ipPortParts[1], out var parsedPort))
                    {
                        tcpPort = parsedPort;
                    }

                    if (string.IsNullOrWhiteSpace(tcpIp))
                    {
                        continue;
                    }
                    
                    // 检查 TCP/IP RAW 打印机的IP地址是否与客户机在同一网段
                    if (localNetworks != null && localNetworks.Count > 0)
                    {
                        if (IPAddress.TryParse(tcpIp, out var tcpIpAddress))
                        {
                            if (!IsInSameNetwork(tcpIpAddress, localNetworks))
                            {
                                // TCP/IP RAW 打印机的IP不在同一网段，跳过
                                continue;
                            }
                        }
                    }

                    list.Add(new DiscoveredPrinter
                    {
                        ServerName = serverName,
                        ServerIp = ip,
                        Port = port,
                        DisplayName = pName,
                        Uri = $"tcp://{tcpIp}:{tcpPort}", // 用于显示
                        PrinterType = "TCP_RAW",
                        TcpIp = tcpIp,
                        TcpPort = tcpPort
                    });
                }
            }

            return list;
        }

        private static string RemoveQueueSuffix(string displayName)
        {
            if (string.IsNullOrWhiteSpace(displayName))
            {
                return string.Empty;
            }

            var trimmed = displayName.Trim();
            var idx = trimmed.LastIndexOf(" (", StringComparison.Ordinal);
            if (idx > 0 && trimmed.EndsWith(")", StringComparison.Ordinal))
            {
                return trimmed.Substring(0, idx).TrimEnd();
            }

            return trimmed;
        }

        private Bitmap LoadPrinterBitmap()
        {
            // 1. 优先从嵌入资源中加载 printer.png（不依赖外部文件）
            try
            {
                var asm = typeof(MainForm).Assembly;
                // 资源名通常为 根命名空间.文件夹.文件名
                var resourceName = "IppPrinterInstallHelper.Resources.printer.png";
                using (var stream = asm.GetManifestResourceStream(resourceName))
                {
                    if (stream != null)
                    {
                        return new Bitmap(stream);
                    }
                }
            }
            catch
            {
            }

            // 2. 退回到系统内置的打印机图标
            try
            {
                var info = new SHSTOCKICONINFO();
                info.cbSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(SHSTOCKICONINFO));
                var hr = SHGetStockIconInfo(SIID_PRINTER, SHGSI_ICON | SHGSI_LARGEICON, ref info);
                if (hr == 0 && info.hIcon != IntPtr.Zero)
                {
                    using (var icon = Icon.FromHandle(info.hIcon))
                    {
                        var bmp = icon.ToBitmap();
                        IconExtractor.DestroyIcon(info.hIcon);
                        return bmp;
                    }
                }
            }
            catch
            {
            }

            // 3. 最后兜底：通用应用程序图标
            return SystemIcons.Application.ToBitmap();
        }

        #region Native

        private const int SIID_PRINTER = 16;
        private const uint SHGSI_ICON = 0x000000100;
        private const uint SHGSI_LARGEICON = 0x000000000;
        private const int SW_SHOWNORMAL = 1;

        [System.Runtime.InteropServices.DllImport("Shell32.dll", CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
        private static extern int SHGetStockIconInfo(int siid, uint uFlags, ref SHSTOCKICONINFO psii);

        [System.Runtime.InteropServices.DllImport("user32.dll")]
        private static extern bool SetForegroundWindow(IntPtr hWnd);

        [System.Runtime.InteropServices.DllImport("user32.dll")]
        private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);

        [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
        private struct SHSTOCKICONINFO
        {
            public uint cbSize;
            public IntPtr hIcon;
            public int iSysIconIndex;
            public int iIcon;
            public System.Drawing.Rectangle rc;
            public uint dwState;
            public uint dwAttr;
            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 260)]
            public string szDisplayName;
            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 80)]
            public string szTypeName;
        }

        #endregion

        private static class IconExtractor
        {
            [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
            public static extern bool DestroyIcon(IntPtr hIcon);

            [System.Runtime.InteropServices.DllImport("shell32.dll", CharSet = System.Runtime.InteropServices.CharSet.Unicode, EntryPoint = "ExtractIconExW")]
            private static extern uint ExtractIconEx(string lpszFile, int nIconIndex, IntPtr[] phiconLarge, IntPtr[] phiconSmall, uint nIcons);

            public static Icon Extract(string path, int index, bool loadLarge)
            {
                var icons = new IntPtr[1];
                var result = ExtractIconEx(path, index, loadLarge ? icons : null, loadLarge ? null : icons, 1);
                if (result > 0 && icons[0] != IntPtr.Zero)
                {
                    var icon = (Icon)Icon.FromHandle(icons[0]).Clone();
                    DestroyIcon(icons[0]);
                    return icon;
                }
                return null;
            }
        }

        private sealed class DiscoveredPrinter
        {
            public string ServerName { get; set; }
            public string ServerIp { get; set; }
            public string Port { get; set; }
            public string DisplayName { get; set; }
            public string Uri { get; set; }
            /// <summary>
            /// 打印机类型：IPP 或 TCP_RAW
            /// </summary>
            public string PrinterType { get; set; } = "IPP";
            /// <summary>
            /// TCP/IP RAW 打印机的 IP 地址（仅当 PrinterType 为 TCP_RAW 时有效）
            /// </summary>
            public string TcpIp { get; set; }
            /// <summary>
            /// TCP/IP RAW 打印机的端口（仅当 PrinterType 为 TCP_RAW 时有效）
            /// </summary>
            public int TcpPort { get; set; }
        }

        // 不再需要手动输入打印机名称的对话框，保持主界面简单
    }
}


